package com.study.app.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.study.app.domain.AppUserInfoSet;
import com.study.app.mapper.AppUserInfoSetMapper;
import com.study.app.mapper.AppUserInvitationRecordMapper;
import com.study.app.mapper.AppUserMapper;
import com.study.app.service.IAppRegisterService;
import com.study.common.core.domain.model.AppEmailRegisterBody;
import com.study.common.core.domain.model.AppLoginUser;
import com.study.common.core.domain.model.AppRegisterBody;
import com.study.common.enums.UserType;
import com.study.common.exception.ServiceException;
import com.study.common.helper.AppLoginHelper;
import com.study.common.utils.AesGcmUtils;
import com.study.common.utils.DateUtils;
import com.study.common.utils.MessageUtils;
import com.study.common.utils.RedisKeyUtils;
import com.study.common.utils.redis.RedisUtils;
import com.study.app.domain.AppUser;
import com.study.app.domain.AppUserInvitationRecord;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Random;

@Slf4j
@RequiredArgsConstructor
@Service
public class AppRegisterServiceImpl implements IAppRegisterService {

    private final AppUserMapper appUserMapper;
    private final AppUserInvitationRecordMapper appUserInvitationRecordMapper;
    private final AppUserInfoSetMapper appUserInfoSetMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String register(AppRegisterBody appRegisterBody) {
            String key = RedisKeyUtils.getAppSmsRegisterCode(appRegisterBody.getPhone());
            // 校验
            checkCode(key, appRegisterBody.getCode());

            AppUser appUser = appUserMapper.selectOne(Wrappers.<AppUser>query().lambda()
                    .eq(AppUser::getUserPhone, AesGcmUtils.encrypt(appRegisterBody.getPhone())));
            if (appUser != null) {
                throw new ServiceException(MessageUtils.message("account.has.been.registered"));
            }

            AppUser registerUser = new AppUser();
            registerUser.setUserCode(IdUtil.simpleUUID());
            registerUser.setAreaCode(appRegisterBody.getAreaCode());
            registerUser.setUserPhone(AesGcmUtils.encrypt(appRegisterBody.getPhone()));
            registerUser.setUserPassword(AesGcmUtils.encrypt(appRegisterBody.getPassword()));
            registerUser.setUserNike("ST" + RandomUtil.randomInt(1000, 9999));
            registerUser.setInvitationCode(generateInvitationCode());
            registerUser.setAppType(appRegisterBody.getAppType());
            registerUser.setCreateTime(DateUtils.getNowDate());
            appUserMapper.insert(registerUser);
            //用户消息开关数据添加
            AppUserInfoSet userInfo = new AppUserInfoSet();
            userInfo.setUserCode(registerUser.getUserCode());
            userInfo.setElectricFence(0);
            userInfo.setExpirationReminder(0);
            userInfo.setRenewalNotice(0);
            userInfo.setTheftAlarm(0);
            userInfo.setElectricFence(0);
            userInfo.setIllegalMovement(0);
            appUserInfoSetMapper.insert(userInfo);




        // 推荐码
            if (StrUtil.isNotEmpty(registerUser.getInvitationCode())) {
                // 根据邀请码找到具体的人
                AppUser invitationAppUser = appUserMapper.selectOne(Wrappers.<AppUser>query().lambda()
                        .eq(AppUser::getInvitationCode, appRegisterBody.getInvitationCode()));
                if (invitationAppUser != null) {
                    AppUserInvitationRecord appUserInvitationRecord = new AppUserInvitationRecord();
                    appUserInvitationRecord.setUserId(invitationAppUser.getId());
                    appUserInvitationRecord.setInvitationUserId(registerUser.getId());
                    appUserInvitationRecord.setInvitationPhone(registerUser.getUserPhone());
                    appUserInvitationRecordMapper.insert(appUserInvitationRecord);
                } else {
                    log.info("邀请码不存在: {}", appRegisterBody.getInvitationCode());
                }
            }

            // 跳转登录
            AppUser user = appUserMapper.selectById(registerUser.getId());
            // 此处可根据登录用户的数据不同 自行创建 loginUser
            AppLoginUser loginUser = buildLoginUser(user);
            // 生成token
            AppLoginHelper.login(loginUser);

            // 删除key
            RedisUtils.deleteObject(key);

            return StpUtil.getTokenValue();
    }

    @Override
    public String emailRegister(AppEmailRegisterBody appEmailRegisterBody) {
        String key = RedisKeyUtils.getAppEmailRegisterCode(appEmailRegisterBody.getEmail());

        // 校验
        checkCode(key, appEmailRegisterBody.getCode());

        AppUser appUser = appUserMapper.selectOne(Wrappers.<AppUser>query().lambda()
                .eq(AppUser::getUserEmail, AesGcmUtils.encrypt(appEmailRegisterBody.getEmail())));
        if (appUser != null) {
            throw new ServiceException(MessageUtils.message("account.has.been.registered"));
        }

        AppUser registerUser = new AppUser();
        registerUser.setUserCode(IdUtil.simpleUUID());
        registerUser.setUserEmail(AesGcmUtils.encrypt(appEmailRegisterBody.getEmail()));
        registerUser.setUserPassword(AesGcmUtils.encrypt(appEmailRegisterBody.getPassword()));
        registerUser.setUserNike("MG" + RandomUtil.randomInt(1000, 9999));
        registerUser.setInvitationCode(generateInvitationCode());
        registerUser.setAppType(appEmailRegisterBody.getAppType());
        registerUser.setMapType(appEmailRegisterBody.getMapType());
        registerUser.setLanguageIden(appEmailRegisterBody.getLanguage());
        registerUser.setCreateTime(DateUtils.getNowDate());
        //用户消息开关数据添加
        appUserMapper.insert(registerUser);
        AppUserInfoSet userInfo = new AppUserInfoSet();
        userInfo.setUserCode(registerUser.getUserCode());
        userInfo.setElectricFence(0);
        userInfo.setExpirationReminder(0);
        userInfo.setRenewalNotice(0);
        userInfo.setTheftAlarm(0);
        userInfo.setElectricFence(0);
        userInfo.setIllegalMovement(0);
        appUserInfoSetMapper.insert(userInfo);
        // 推荐码
        if (StrUtil.isNotEmpty(registerUser.getInvitationCode())) {
            // 根据邀请码找到具体的人
            AppUser invitationAppUser = appUserMapper.selectOne(Wrappers.<AppUser>query().lambda()
                    .eq(AppUser::getInvitationCode, appEmailRegisterBody.getInvitationCode()));
            if (invitationAppUser != null) {
                AppUserInvitationRecord appUserInvitationRecord = new AppUserInvitationRecord();
                appUserInvitationRecord.setUserId(invitationAppUser.getId());
                appUserInvitationRecord.setInvitationUserId(registerUser.getId());
                appUserInvitationRecord.setInvitationPhone(registerUser.getUserPhone());
                appUserInvitationRecordMapper.insert(appUserInvitationRecord);
            } else {
                log.info("邀请码不存在: {}", appEmailRegisterBody.getInvitationCode());
            }
        }


        // 跳转登录
        AppUser user = appUserMapper.selectById(registerUser.getId());
        // 此处可根据登录用户的数据不同 自行创建 loginUser
        AppLoginUser loginUser = buildLoginUser(user);
        // 生成token
        AppLoginHelper.login(loginUser);

        // 删除key
        RedisUtils.deleteObject(key);

        return StpUtil.getTokenValue();
    }

    /**
     * 构建登录用户
     */
    private AppLoginUser buildLoginUser(AppUser user) {
        AppLoginUser loginUser = new AppLoginUser();
        loginUser.setUserId(user.getId());
        loginUser.setUserCode(user.getUserCode());
        loginUser.setUserType(UserType.APP_USER.getUserType());
        loginUser.setAreaCode(user.getAreaCode());
        loginUser.setUserPhone(user.getUserPhone());
        loginUser.setUserEmail(user.getUserEmail());
        loginUser.setToken(StpUtil.getTokenValue());
        loginUser.setLoginTime(System.currentTimeMillis());
        return loginUser;
    }

    public String generateInvitationCode() {
        String invitationCode = generateCode(7);
        long count = appUserMapper.selectCount(Wrappers.<AppUser>query().lambda()
                .eq(AppUser::getInvitationCode, invitationCode));
        if (count > 0) {
            return generateInvitationCode();
        }
        return invitationCode;
    }

    /**
     * 使用指定源生成验证码
     *
     * @param verifySize 验证码长度
     * @return 7位字符
     */
    public String generateCode(int verifySize) {
        /*
         * 使用到Algerian字体，系统里没有的话需要安装字体，字体只显示大写，去掉了1,0,i,o几个容易混淆的字符
         */
        String verifyCodes = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
        int codesLen = verifyCodes.length();
        Random rand = new Random(System.currentTimeMillis());
        StringBuilder verifyCode = new StringBuilder(verifySize);
        for (int i = 0; i < verifySize; i++) {
            verifyCode.append(verifyCodes.charAt(rand.nextInt(codesLen - 1)));
        }
        return verifyCode.toString();
    }


    /**
     * 校验验证码
     *
     * @param key         键
     * @param code        验证码
     */
    public void checkCode(String key, String code) {
        if (!RedisUtils.hasKey(key)) {
            throw new ServiceException(MessageUtils.message("verification.code.expired"));
        }

        String value = RedisUtils.getCacheObject(key);
        if (!code.equals(value)) {
            throw new ServiceException(MessageUtils.message("verification.code.error"));
        }
    }

}
